package com.chezai.client.fragment;

import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.hardware.Camera;
import android.hardware.usb.UsbManager;
import android.location.Location;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.ali.show.NetWorkUtils;
import com.alivc.live.pusher.AlivcAudioAACProfileEnum;
import com.alivc.live.pusher.AlivcAudioChannelEnum;
import com.alivc.live.pusher.AlivcEncodeModeEnum;
import com.alivc.live.pusher.AlivcFpsEnum;
import com.alivc.live.pusher.AlivcLivePushCameraTypeEnum;
import com.alivc.live.pusher.AlivcLivePushConfig;
import com.alivc.live.pusher.AlivcLivePushStatsInfo;
import com.alivc.live.pusher.AlivcLivePusher;
import com.alivc.live.pusher.SurfaceStatus;
import com.chezai.client.R;
import com.chezai.client.activitys.CameraActivity;
import com.chezai.client.activitys.TwoAndThreeActivity;
import com.chezai.client.bean.ClassRecord;
import com.chezai.client.bean.CoachLoginRecord;
import com.chezai.client.bean.EndSupplementPhotoResult;
import com.chezai.client.bean.GpsStatusEntity;
import com.chezai.client.bean.LedBean;
import com.chezai.client.bean.ObdConnState;
import com.chezai.client.bean.PeriodRecord;
import com.chezai.client.bean.RandomPhoto;
import com.chezai.client.bean.RetryUploadPhoto;
import com.chezai.client.bean.RetryUploadResult;
import com.chezai.client.bean.SecondLocation;
import com.chezai.client.bean.Speech;
import com.chezai.client.bean.StudentStudyRecord;
import com.chezai.client.bean.TakePhotoEntity;
import com.chezai.client.bean.TerminalBaseInfo;
import com.chezai.client.bean.TrainProjectEntity;
import com.chezai.client.bean.UserInfo;
import com.chezai.client.dao.manager.ClassRecordDaoManager;
import com.chezai.client.dao.manager.CoachLoginRecordDaoManager;
import com.chezai.client.dao.manager.PeriodRecordDaoManager;
import com.chezai.client.dao.manager.RandomPhotoDaoManager;
import com.chezai.client.dao.manager.StudentStudyRecordDaoManager;
import com.chezai.client.dao.manager.TerminalBaseInfoDaoManager;
import com.chezai.client.dao.manager.TerminalParameterDaoManager;
import com.chezai.client.dao.manager.TrainProjectEntityManager;
import com.chezai.client.global.Const;
import com.chezai.client.global.DeviceFactory;
import com.chezai.client.global.LogService;
import com.chezai.client.global.NetConst;
import com.chezai.client.global.PolygonManager;
import com.chezai.client.global.TerminalApplication;
import com.chezai.client.global.location.LocationMgr;
import com.chezai.client.inter.OnTimerListener;
import com.chezai.client.server.TerminalSocketClientManager;
import com.chezai.client.server.TerminalSocketClientManager_8001;
import com.chezai.client.server.util.TransmissionMessageUtil;
import com.chezai.client.utils.BuildDataUtil;
import com.chezai.client.utils.CameraMgr;
import com.chezai.client.utils.DateUtil;
import com.chezai.client.utils.DeviceUtils;
import com.chezai.client.utils.DialogUtils;
import com.chezai.client.utils.LocationUtils;
import com.chezai.client.utils.PreferenceManager;
import com.chezai.client.utils.SpeechUtils;
import com.chezai.client.utils.ThreadManager;
import com.chezai.client.utils.Util;
import com.chezai.client.widget.ListDialog;
import com.chezai.client.widget.NormalAlertDialog;
import com.chezai.client.widget.TimerTextView;
import com.elm327.ObdService;
import com.google.gson.Gson;
import com.jx.driving.request.Terminal0x0900Request;
import com.jx.driving.response.AbstractResponse;
import com.jx.driving.transmission.Terminal0x0202Transmission;
import com.jx.driving.transmission.Terminal0x0203Transmission;
import com.jx.driving.transmission.Terminal0x0301Transmission;
import com.jx.driving.transmission.Terminal0x0305Transmission;
import com.jx.driving.transmission.Terminal0x8202Transmission;
import com.orhanobut.logger.Logger;

import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.xutils.common.Callback;
import org.xutils.http.RequestParams;
import org.xutils.x;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.ref.WeakReference;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import butterknife.BindView;
import butterknife.OnClick;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import tw.com.prolific.driver.pl2303.PL2303Driver;

import static com.alivc.live.pusher.AlivcPreviewOrientationEnum.ORIENTATION_LANDSCAPE_HOME_LEFT;
import static com.alivc.live.pusher.AlivcPreviewOrientationEnum.ORIENTATION_LANDSCAPE_HOME_RIGHT;

/**
 * 学车页
 * Created by likunyang on 2017/9/13.
 */

public class LearnCarFragment extends BaseFragment implements OnTimerListener, ListDialog.OnItemClickListener, NormalAlertDialog.OnNormalAlertDialogListener {
    public static final int REQ_CODE_PUSH = 0x1112;
    public static final int CAPTURE_PERMISSION_REQUEST_CODE = 0x1123;
    private static final int FLING_MIN_DISTANCE = 50;
    private static final int FLING_MIN_VELOCITY = 0;
    private static final String URL_KEY = "url_key";
    private static final String ASYNC_KEY = "async_key";
    private static final String AUDIO_ONLY_KEY = "audio_only_key";
    private static final String VIDEO_ONLY_KEY = "video_only_key";
    private static final String ORIENTATION_KEY = "orientation_key";
    private static final String CAMERA_ID = "camera_id";
    private static final String FLASH_ON = "flash_on";
    private static final String AUTH_TIME = "auth_time";
    private static final String PRIVACY_KEY = "privacy_key";
    private static final String MIX_EXTERN = "mix_extern";
    private static final String MIX_MAIN = "mix_main";
    private static String CLASS_RECORD_ID = "classRecord_Id";
    private static String IS_END_TRAIN = "isEndTrain";
    private static int TAG_SUPPLEMENT_ALERT = 1;
    private static int TAG_DEFAULT = 2;
    private final long REFRESH_INTERVAL = 1000;
    public SurfaceView mPreviewView;

    @BindView(R.id.btn_server)
    ImageButton btnServer;
    @BindView(R.id.tv_server)
    TextView tvServer;
    @BindView(R.id.btn_gps)
    ImageButton btnGps;
    @BindView(R.id.tv_gps)
    TextView tvGps;
    @BindView(R.id.btn_odb)
    ImageButton btnOdb;
    @BindView(R.id.tv_odb)
    TextView tvObd;
    @BindView(R.id.tv_start_time)
    TextView tvStartTime;
    @BindView(R.id.tv_train_long)
    TimerTextView tvTrainLong;
    @BindView(R.id.tv_course_num)
    TextView tvCourseNum;
    @BindView(R.id.tv_average_speed)
    TextView tvAverageSpeed;
    @BindView(R.id.btn_end_teach)
    Button btnEndTeach;
    /***** 测试使用 Start ******/
    @BindView(R.id.btn_debug)
    Button btnDebug;
    @BindView(R.id.ll_debug)
    LinearLayout llDebug;
    @BindView(R.id.tv_rotate_speed)
    TextView tvRotateSpeed;
    @BindView(R.id.tv_speed)
    TextView tvSpeed;
    @BindView(R.id.tv_min_speed)
    TextView tvMinSpeedKm;
    @BindView(R.id.tv_min_speed_hm)
    TextView tvMinSpeedHm;
    @BindView(R.id.tv_min_mileage)
    TextView tvMinMileage;
    @BindView(R.id.tv_lat)
    TextView tvLat;
    @BindView(R.id.tv_acc)
    TextView tvAcc;
    @BindView(R.id.tv_lon)
    TextView tvLon;
    @BindView(R.id.tv_total_mile)
    TextView tvTotalMile;
    @BindView(R.id.tv_provider)
    TextView tvProvider;
    ScheduledExecutorService mExecutorService = new ScheduledThreadPoolExecutor(5,
            new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
    AlivcLivePushStatsInfo alivcLivePushStatsInfo = null;
    private Location preLocation;
    /***** 测试使用 End ******/
    private long classRecordId;
    private ClassRecord classRecord;
    private UserInfo mStudentInfo;
    private UserInfo coachInfo;
    private boolean mIsCalcTime = true;//是否在围栏内
    private volatile float oneMinuteMaxSpeed;//一分钟内最大速度
    private volatile float oneMinuteMile;//一分钟多少米
    private volatile float learnTotalMile = 0;//本次学车总里程 单位 m
    private volatile float totalMileage;//设备总里程 对应TermianlParameter 128
    private TransmissionMessageUtil messageUtil;

    /////////////////////////
    private Long coachLoginRecordId;
    private TwoAndThreeActivity mActivity;
    private SparseArray<Long> periodRecordTempArray = new SparseArray<>();
    private List<Long> endRetryPeriodRecordIds = new ArrayList<>();
    private Long studyLoginRecordId;
    private int mRotate;//转速
    private boolean isObdConnSucess;//obd是否匹配成功
    private EndTrainRunnable runnable;
    private Handler mHandler;
    private boolean isSimulate;//是否为模拟终端，true:是，false:不是
    private boolean isEndTrain;
    private NormalAlertDialog normalAlertDialog;
    private float tempOneMinuteMaxSpeed;
    private float tempOneMinuteMile;
    private long mSingInTime;
    private int mIntervalTime;//抓拍时间间隔秒
    private Disposable mIntervalTimeDisposable;
    private boolean isTaked;//这一分钟内是否 已经抓拍了照片
    private CopyOnWriteArrayList<RandomPhoto> noHavePhotoPathRecords = new CopyOnWriteArrayList<>();
    private String mAuthString = "?auth_key=%1$d-%2$d-%3$d-%4$s";
    private String mMd5String = "%1$s-%2$d-%3$d-%4$d-%5$s";
    private String mTempUrl = null;
    private String mAuthTime = "";
    private String mPrivacyKey = "UgEkDzrmcs";
    private String mPushUrl = "";
    private GestureDetector mDetector;
    private ScaleGestureDetector mScaleDetector;
    private AlivcLivePushConfig mAlivcLivePushConfig;
    private AlivcLivePusher mAlivcLivePusher = null;
    private boolean mAsync = false;
    private boolean mAudioOnly = false;
    private boolean mVideoOnly = false;
    private int mOrientation = ORIENTATION_LANDSCAPE_HOME_RIGHT.ordinal();
    private SurfaceStatus mSurfaceStatus = SurfaceStatus.UNINITED;
    private boolean isPause = false;
    private int mCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
    private boolean mFlash = false;
    private boolean mMixExtern = false;
    private boolean mMixMain = false;
    private Button mPreviewButton;
    private Button mPushButton;
    private Button mOperaButton;
    private Button mRestartButton;


    private Handler mLedHandler;
    private Runnable ledRunnable;
    private Callback.Cancelable cancelable;


    //    private ConnectivityChangedReceiver mChangedReceiver = new ConnectivityChangedReceiver();
    private boolean videoThreadOn = false;
    private boolean audioThreadOn = false;

    private int mNetWork = 0;
    private GestureDetector.OnGestureListener mGestureDetector = new GestureDetector.OnGestureListener() {
        @Override
        public boolean onDown(MotionEvent motionEvent) {
            return false;
        }

        @Override
        public void onShowPress(MotionEvent motionEvent) {

        }

        @Override
        public boolean onSingleTapUp(MotionEvent motionEvent) {
            if (mPreviewView.getWidth() > 0 && mPreviewView.getHeight() > 0) {
                float x = motionEvent.getX() / mPreviewView.getWidth();
                float y = motionEvent.getY() / mPreviewView.getHeight();
                try {
                    mAlivcLivePusher.focusCameraAtAdjustedPoint(x, y, true);
                } catch (IllegalStateException e) {

                }
            }
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
            return false;
        }

        @Override
        public void onLongPress(MotionEvent motionEvent) {

        }

        @Override
        public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
            if (motionEvent == null || motionEvent1 == null) {
                return false;
            }
            if (motionEvent.getX() - motionEvent1.getX() > FLING_MIN_DISTANCE
                    && Math.abs(v) > FLING_MIN_VELOCITY) {
                // Fling left
            } else if (motionEvent1.getX() - motionEvent.getX() > FLING_MIN_DISTANCE
                    && Math.abs(v) > FLING_MIN_VELOCITY) {
                // Fling right
            }
            return false;
        }
    };
    //////////////////////////
    private float scaleFactor = 1.0f;
    private ScaleGestureDetector.OnScaleGestureListener mScaleGestureDetector = new ScaleGestureDetector.OnScaleGestureListener() {
        @Override
        public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
            if (scaleGestureDetector.getScaleFactor() > 1) {
                scaleFactor += 0.5;
            } else {
                scaleFactor -= 2;
            }
            if (scaleFactor <= 1) {
                scaleFactor = 1;
            }
            try {
                if (scaleFactor >= mAlivcLivePusher.getMaxZoom()) {
                    scaleFactor = mAlivcLivePusher.getMaxZoom();
                }
                mAlivcLivePusher.setZoom((int) scaleFactor);

            } catch (IllegalStateException e) {

            }
            return false;
        }

        @Override
        public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {

        }
    };
    private PL2303Driver mSerial;
    private static final String ACTION_USB_PERMISSION = "com.prolific.pl2303hxdsimpletest.USB_PERMISSION";


    /**
     * @param _id        培训记录ID
     * @param isEndTrain 是否结束训练 true 结束，false 继续训练
     * @return this
     */
    public static LearnCarFragment newInstance(long _id, boolean isEndTrain) {
        Bundle args = new Bundle();
        args.putLong(CLASS_RECORD_ID, _id);
        args.putBoolean(IS_END_TRAIN, isEndTrain);
        LearnCarFragment fragment = new LearnCarFragment();
        fragment.setArguments(args);
        return fragment;
    }

    private AlivcLivePushConfig setAlivcLivePushConfig() {
        AlivcLivePushConfig alivcLivePushConfig = new AlivcLivePushConfig();
        alivcLivePushConfig.setFps(AlivcFpsEnum.FPS_20);
        alivcLivePushConfig.setPushMirror(true);
        alivcLivePushConfig.setPreviewOrientation(ORIENTATION_LANDSCAPE_HOME_LEFT);
        alivcLivePushConfig.setVideoOnly(false);
        alivcLivePushConfig.setVideoEncodeMode(AlivcEncodeModeEnum.Encode_MODE_HARD);
        alivcLivePushConfig.setAudioOnly(false);
        alivcLivePushConfig.setAudioProfile(AlivcAudioAACProfileEnum.HE_AAC);
        alivcLivePushConfig.setAudioBitRate(64000);
        alivcLivePushConfig.setAudioEncodeMode(AlivcEncodeModeEnum.Encode_MODE_HARD);
        alivcLivePushConfig.setAudioChannels(AlivcAudioChannelEnum.AUDIO_CHANNEL_TWO);
        alivcLivePushConfig.setCameraType(AlivcLivePushCameraTypeEnum.CAMERA_TYPE_FRONT);
        alivcLivePushConfig.setAutoFocus(false);
        alivcLivePushConfig.setEnableAutoResolution(true);
        return alivcLivePushConfig;
    }

    @Override
    public void onResume() {
        super.onResume();
//        if (!mSerial.isConnected()) {
//            if (!mSerial.enumerate()) {
//                Toast.makeText(TerminalApplication.getTerminalContext(), "no more devices found", Toast.LENGTH_SHORT).show();
//                return;
//            } else {
//                Log.d(TAG, "onResume:enumerate succeeded!");
//            }
//        }//if isConnected
//        Toast.makeText(TerminalApplication.getTerminalContext(), "attached", Toast.LENGTH_SHORT).show();


        Const.IS_TRAINING = true;
        EventBus.getDefault().register(this);
        resumePush();
    }

    @Override
    public void onPause() {
        super.onPause();
        Const.IS_TRAINING = false;
        EventBus.getDefault().unregister(this);
        pausePush();
    }

    //////////////////////////////////////
    @Override
    public void onDestroy() {



        if (tvTrainLong != null) {
            tvTrainLong.unRegisterTimerListner();
        }
        ////////////////////////////
        videoThreadOn = false;
        audioThreadOn = false;
        if (mAlivcLivePusher != null) {
            try {
                mAlivcLivePusher.destroy();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            }
        }
        mPreviewView = null;
        mDetector = null;
        mScaleDetector = null;
        mAlivcLivePushConfig = null;

        mAlivcLivePusher = null;
        alivcLivePushStatsInfo = null;
//        if (mSerial != null) {
//            mSerial.end();
//            mSerial = null;
//        }
        ////////////////////////////
        super.onDestroy();
        /////////////////////////////
        if (mExecutorService != null && !mExecutorService.isShutdown()) {
            mExecutorService.shutdown();
        }
        /////////////////////////////
        mActivity = null;
        PolygonManager.getInstance().unRegisterPolygonEvent();

    }

    @Override
    public int getLayoutId() {
        return R.layout.fragment_learn_car;
    }

    @Override
    public void initView(Bundle savedInstanceState) {
        isSimulate = TerminalBaseInfoDaoManager.getInstance().getTerminalType() == Const.SIMULATE_TYPE;
        mActivity = (TwoAndThreeActivity) getActivity();
        DeviceFactory.hardware.controlRelay(true);
        mIntervalTime = PreferenceManager.getInt(Const.SP_INTERVAL_TIME, 15);
        btnServer.setSelected(TerminalSocketClientManager.getInstance().isConnect());
        tvServer.setText(TerminalSocketClientManager.getInstance().isConnect() ? "正常" : "断开");
        Bundle bundle = getArguments();
        classRecordId = bundle.getLong(CLASS_RECORD_ID);
        boolean isEndTrain = bundle.getBoolean(IS_END_TRAIN);
        classRecord = ClassRecordDaoManager.getInstance().findClassRecord(classRecordId);
        BuildDataUtil.setStudentClassId(classRecord.getClassId());
        learnTotalMile = classRecord.getMileage();
        tvCourseNum.setText(String.format("%.1fkm", learnTotalMile / 1000.0f));
        mStudentInfo = classRecord.getUserInfo();
        mSingInTime = classRecord.getSignInTime();
        StudentStudyRecord studyRecord = StudentStudyRecordDaoManager.getInstance().findStudentLoginRecordByClassRecordId(classRecordId);
        studyLoginRecordId = studyRecord.get_ID();
        coachLoginRecordId = studyRecord.getCoachLoginRecordId();
        CoachLoginRecord coachLoginRecord = CoachLoginRecordDaoManager.getInstance().findCoachLoginRecord(coachLoginRecordId);
        coachInfo = coachLoginRecord.getCoachInfo();
        totalMileage = TerminalParameterDaoManager.getInstance().getTerminalParameter128();
        tvStartTime.setText(DateUtil.timestampStr(classRecord.getSignInTime(), DateUtil.sf4));
        long studyValidLong = classRecord.getStudyValidLong();
        tvTrainLong.setStartTime(studyValidLong, TimeUnit.SECONDS);
        if (isEndTrain) {
            endTrain();
        } else {
            tvTrainLong.setOnTimerListener(this);
            tvTrainLong.start();
            initTakeLearningPhoto();
            if (!isSimulate) {//如果为模拟终端，则不注册出围栏警告
                PolygonManager.getInstance().registerPolygonEvent();
                PolygonManager.getInstance().getPolygon((short) classRecord.getTrainPart());
            }
        }
        initShow();
        // 启动 obd
        Intent intent = new Intent();
        intent.setClass(TerminalApplication.mContext, ObdService.class);
        TerminalApplication.mContext.startService(intent);
        Log.e("harisucici:OBD", "启动 obd");

        //推大屏
//        // get service
//        mSerial = new PL2303Driver((UsbManager) TerminalApplication.getTerminalContext().getSystemService(Context.USB_SERVICE),
//                TerminalApplication.getTerminalContext(), ACTION_USB_PERMISSION);
//
//        // check USB host function.
//        if (!mSerial.PL2303USBFeatureSupported()) {
//            Toast.makeText(TerminalApplication.getTerminalContext(), "No Support USB host API", Toast.LENGTH_SHORT).show();
//            Log.d(TAG, "No Support USB host API");
//            mSerial = null;
//
//        }
//
//        if (mLedHandler == null) {
//            mLedHandler = new Handler();
//            ledRunnable = new LedRunnable(mLedHandler, mSerial);
//
//        }
//        mLedHandler.postDelayed(ledRunnable, 1000);
        startPush();

    }

    public void startYUV(final Context context) {
        new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
            private AtomicInteger atoInteger = new AtomicInteger(0);

            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setName("LivePushActivity-readYUV-Thread" + atoInteger.getAndIncrement());
                return t;
            }
        }).execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                videoThreadOn = true;
                byte[] yuv;
                InputStream myInput = null;
                try {
                    File f = new File(Environment.getExternalStorageDirectory().getPath() + File.separator + "alivc_resource/capture0.yuv");
                    myInput = new FileInputStream(f);
                    byte[] buffer = new byte[1280 * 720 * 3 / 2];
                    int length = myInput.read(buffer);
                    //发数据
                    while (length > 0 && videoThreadOn) {
                        mAlivcLivePusher.inputStreamVideoData(buffer, 720, 1280, 720, 1280 * 720 * 3 / 2, System.nanoTime() / 1000, 0);
                        try {
                            Thread.sleep(40);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //发数据
                        length = myInput.read(buffer);
                        if (length <= 0) {
                            myInput.close();
                            myInput = new FileInputStream(f);
                            length = myInput.read(buffer);
                        }
                    }
                    myInput.close();
                    videoThreadOn = false;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private void stopYUV() {
        videoThreadOn = false;
    }

    private void stopPCM() {
        audioThreadOn = false;
    }

    private void initShow() {
        mPushUrl = PreferenceManager.getString("SHOWURL", "");
        myLog(mPushUrl);
        mAsync = true;
        mAudioOnly = false;
        mVideoOnly = true;
        mCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
        mFlash = false;
        mMixExtern = false;
        mMixMain = false;
        mAlivcLivePushConfig = setAlivcLivePushConfig();
        mAlivcLivePusher = new AlivcLivePusher();

        try {
            mAlivcLivePusher.init(TerminalApplication.mContext, mAlivcLivePushConfig);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
        mScaleDetector = new ScaleGestureDetector(TerminalApplication.mContext, mScaleGestureDetector);
        mDetector = new GestureDetector(TerminalApplication.mContext, mGestureDetector);
        mNetWork = NetWorkUtils.getAPNType(TerminalApplication.mContext);
    }

    private String getAuthString(String time) {
        if (!time.isEmpty() && !mPrivacyKey.isEmpty()) {
            TerminalBaseInfo baseInfo = TerminalBaseInfoDaoManager.getInstance().getTerminalBaseInfo();
            long tempTime = (System.currentTimeMillis() + Integer.valueOf(time)) / 1000;
            String tempprivacyKey = String.format(mMd5String, mPushUrl, tempTime, 0, 0, mPrivacyKey);
            String auth = String.format(mAuthString, tempTime, 0, 0, getMD5(tempprivacyKey));
            mTempUrl = mPushUrl + baseInfo.getInscode() + "/" + baseInfo.getIdentification() + auth;
        } else {
            mPushUrl = mPushUrl;
        }
        return mPushUrl;
    }

    private String getMD5(String string) {

        byte[] hash;

        try {
            hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }

        StringBuilder hex = new StringBuilder(hash.length * 2);
        for (byte b : hash) {
            if ((b & 0xFF) < 0x10) {
                hex.append("0");
            }
            hex.append(Integer.toHexString(b & 0xFF));
        }

        return hex.toString();
    }

    private void myLog(String s) {
        Log.e("harisucici", s);
    }


    private void startPush() {

        myLog("startPush");
        if (mAsync) {
            mAlivcLivePusher.startPushAysnc(getAuthString(mAuthTime));
        } else {
            mAlivcLivePusher.startPush(getAuthString(mAuthTime));
        }
        if (mMixExtern) {
            //startMixPCM(getActivity());
        } else if (mMixMain) {
            startPCM();
        }
    }

    private void stopPush() {
        myLog("startPush");
        if(mAlivcLivePusher!=null){
            mAlivcLivePusher.stopPush();
        }

        stopPCM();
    }

    private void pausePush() {
        myLog("pausePush");
        if (mAlivcLivePusher != null) {
            try {
                if (mAlivcLivePusher != null) {
                    mAlivcLivePusher.pause();
                }
            } catch (IllegalStateException e) {
                e.printStackTrace();
            }
        }
    }

    private void resumePush() {
        if (mAlivcLivePusher != null) {
            try {
                if (!isPause) {
                    myLog("resumePush");
                    if (mAsync) {
                        mAlivcLivePusher.resumeAsync();
                    } else {
                        mAlivcLivePusher.resume();
                    }
                }
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            }
        }
    }

    private void startPCM() {
        new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
            private AtomicInteger atoInteger = new AtomicInteger(0);

            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setName("LivePushActivity-readPCM-Thread" + atoInteger.getAndIncrement());
                return t;
            }
        }).execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                audioThreadOn = true;
                byte[] pcm;
                int allSended = 0;
                int sizePerSecond = 44100 * 2;
                InputStream myInput = null;
                OutputStream myOutput = null;
                boolean reUse = false;
                long startPts = System.nanoTime() / 1000;
                try {
                    File f = new File("/sdcard/alivc_resource/441.pcm");
                    myInput = new FileInputStream(f);
                    byte[] buffer = new byte[2048];
                    int length = myInput.read(buffer, 0, 2048);
                    while (length > 0 && audioThreadOn) {
                        long pts = System.nanoTime() / 1000;
                        mAlivcLivePusher.inputStreamAudioData(buffer, length, 44100, 1, pts);
                        allSended += length;
                        if ((allSended * 1000000L / sizePerSecond - 50000) > (pts - startPts)) {
                            try {
                                Thread.sleep(45);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        length = myInput.read(buffer);
                        if (length < 2048) {
                            myInput.close();
                            myInput = new FileInputStream(f);
                            length = myInput.read(buffer);
                        }
                        try {
                            Thread.sleep(3);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    myInput.close();
                    audioThreadOn = false;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private String getUri(String url) {
        String result = "";
        String temp = url.substring(7);
        if (temp != null && !temp.isEmpty()) {
            result = temp.substring(temp.indexOf("/"));
        }
        return result;
    }

    //////////////////////////////////////
    public void getStopUrl() {
        Callback.Cancelable cancelable = x.http().get(getUrlParams(), new Callback.CommonCallback<String>() {
            @Override
            public void onSuccess(String result) {
                Logger.t(TAG).i("结束成功。");
                if (result != null) {
                    Logger.t(TAG).e("结束成功。" + result);
//                //harisucici
//                if (!TextUtils.isEmpty(result)) {
//                    Logger.t(TAG).i("最新推流url地址：" + result);
//                    PreferenceManager.putString("SHOWURL", result);
//                    String s = PreferenceManager.getString("SHOWURL", "");
//                    String s1 = PreferenceManager.getString("SHOWURL", "");
//                }
                }
            }

            @Override
            public void onError(Throwable ex, boolean isOnCallback) {
                Logger.t(TAG).e("结束OnError。" + ex.getMessage());
            }

            @Override
            public void onCancelled(CancelledException cex) {
                Logger.t(TAG).i("结束取消。");
            }

            @Override
            public void onFinished() {
                Logger.t(TAG).i("结束Finished");
            }
        });
    }

    private RequestParams getUrlParams() {
        TerminalBaseInfo terminalBaseInfo = TerminalBaseInfoDaoManager.getInstance().getTerminalBaseInfo();
        StringBuilder sb = new StringBuilder();
        sb.append(NetConst.GET_STOP_URL);
        sb.append(terminalBaseInfo.getInscode());
        sb.append("/");
        sb.append(terminalBaseInfo.getDevice());
        Log.e("harisucici", "获取Url:" + sb.toString());
        RequestParams requestParams = new RequestParams(sb.toString());
        return requestParams;
    }

    //学员抓拍，拍照倒计时
    private void initTakeLearningPhoto() {
        Observable.interval(1, TimeUnit.SECONDS)
                .flatMap(new Function<Long, ObservableSource<Boolean>>() {
                    @Override
                    public ObservableSource<Boolean> apply(Long aLong) throws Exception {
                        long totalMinutes = ((System.currentTimeMillis() - mSingInTime) / 1000) / 60;
                        boolean isTakeLearningPhoto = totalMinutes % mIntervalTime == 0;
                        if (isTakeLearningPhoto && isTaked) {
                            isTaked = !isTakeLearningPhoto;
                            return Observable.just(true);
                        }
                        isTaked = !isTakeLearningPhoto;
                        return Observable.just(false);
                    }
                }).observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.computation())
                .subscribe(new Observer<Boolean>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        mIntervalTimeDisposable = d;
                    }

                    @Override
                    public void onNext(Boolean b) {
                        if (b) {
                            disableEndTrain();
                            if (Const.TrainPart.TWO == classRecord.getTrainPart() || Const.TrainPart.THREE == classRecord.getTrainPart()) {
                                SpeechUtils.getInstance().playOrComposed(Speech.SNAPSHOT_REMIND.getMsg(), Speech.SNAPSHOT_REMIND.getFilePath());
                            }
                            LogService.getInstance(TerminalApplication.mContext).sendLog("start take student learning photo! time: " + System.currentTimeMillis());
                            long randomPhotoId = saveRandomPhotoInfo();
                            takeStudentLearningPhoto(randomPhotoId, false);
                        }
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }

    @Override
    public void setListener() {
        if (!NetConst.RELEASE_SERVER) {
            btnDebug.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    if (llDebug.isShown()) {
                        llDebug.setVisibility(View.GONE);
                    } else {
                        llDebug.setVisibility(View.VISIBLE);
                    }
                    return true;
                }
            });
        }
    }

    @Override
    public void initData() {
        messageUtil = new TransmissionMessageUtil();
        if (mHandler == null) {
            mHandler = new Handler();
            runnable = new EndTrainRunnable(btnEndTeach, mHandler);
        }


    }

    @OnClick(R.id.btn_end_teach)
    public void onViewClicked() {
        if (DeviceUtils.isDoubleClick()) {
            return;
        }
        normalAlertDialog = DialogUtils.showSingleButtonAlertDialog(getContext(), "提示", "确认结束训练？", "确定", NormalAlertDialog.Builder.DIALOG_STYLE_NORMAL, 0, this);
    }

    @Override
    public void onNormalAlertDialogClick(NormalAlertDialog dialog, View view, int btnType) {
        dialog.dismiss();
        if (btnType == NormalAlertDialog.NORMAL_ALERT_DIALOG_MIDDLE) {
            getStopUrl();// 上报终止推流

            if (dialog.getTag() == TAG_SUPPLEMENT_ALERT) {
                takeStudentLearningPhoto(noHavePhotoPathRecords.get(0).get_ID(), true);
            } else {
                endTrain();
            }
        }
    }

    /**
     * 结束训练
     */
    private void endTrain() {
        stopPush();// 终止推流
        if (DeviceUtils.isDoubleClick()) {
            return;
        }

        disableEndTrain();
        isEndTrain = true;
        if (mIntervalTimeDisposable != null) {
            mIntervalTimeDisposable.dispose();
        }
        if (tvTrainLong != null) {
            tvTrainLong.stop();
        }
        List<RandomPhoto> list = RandomPhotoDaoManager.getInstance().findNoHavePhotoPathRecord(classRecordId);
        noHavePhotoPathRecords.clear();
        noHavePhotoPathRecords.addAll(list);
        logoutCheckUpDataAndRetry();
    }

    /**
     * 登出前检查数据并尝试重传
     */
    private void logoutCheckUpDataAndRetry() {
        if (TerminalSocketClientManager.getInstance().isAuthenticated() && TerminalSocketClientManager.getInstance().isConnect()) {
            if (noHavePhotoPathRecords.size() == 0) {
                retryUploadData();
            } else {
                showLostPhotoAlert(noHavePhotoPathRecords.size());
            }
        } else {
            showToast("未连接到服务器,请稍后重试");
            TerminalSocketClientManager.getInstance().authenTicate();
        }
    }

    private void disableEndTrain() {
        btnEndTeach.setEnabled(false);
        btnEndTeach.setText("60s后再签退");
        if (mHandler != null) {
            mHandler.post(runnable);
        } else {
            mHandler = new Handler();
            runnable = new EndTrainRunnable(btnEndTeach, mHandler);
            mHandler.post(runnable);
        }
    }

    /**
     * 提示 丢失照片提醒！
     *
     * @param size 多少张丢失照片
     */
    private void showLostPhotoAlert(int size) {
        DialogUtils.showSingleButtonAlertDialog(getContext(), "提示",
                "有" + size + " 张抓拍丢失，是否补拍！", "确定",
                NormalAlertDialog.Builder.DIALOG_STYLE_NORMAL,
                TAG_SUPPLEMENT_ALERT, this);
    }

    @Subscribe(sticky = true)
    public void onEventEndSupplementPhotoResult(EndSupplementPhotoResult endSupplementPhotoResult) {
        EventBus.getDefault().removeStickyEvent(endSupplementPhotoResult);
        for (RandomPhoto randomPhoto : noHavePhotoPathRecords) {
            if (randomPhoto.get_ID() == endSupplementPhotoResult.getRandomPhotoId()) {
                noHavePhotoPathRecords.remove(randomPhoto);
            }
        }
        logoutCheckUpDataAndRetry();
    }

    //重传学时和随机照片
    private void retryUploadData() {
        if (isSimulate) {
            EventBus.getDefault().postSticky(new RetryUploadResult(true, RetryUploadResult.UPLOAD_PERIOD_OVER));
        } else {
            tryUploadPeriod(true);
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void onEventRetryUploadResult(RetryUploadResult result) {
        EventBus.getDefault().removeStickyEvent(result);
        if (result.isEnd) {
            DialogUtils.dismissDialog();
            if (result.code == RetryUploadResult.UPLOAD_PERIOD_OVER) {
                Logger.t("TryUpload").e("重传完所有学时,是否为结束训练 " + result.isEnd);
                tryUploadRandomPhoto(result.isEnd);
            } else if (result.code == RetryUploadResult.UPLOAD_PHOTO_OVER) {
                Logger.t("TryUpload").e("重传完所有随机照片,是否为结束训练 " + result.isEnd);
                takeStudentSignOutPhoto();
            }
        }
    }

    /**
     * 展示选择训练项目弹窗
     */
    public void showSelectTrainSubjectDialog() {
        List<TrainProjectEntity> trainProjectsByPart = TrainProjectEntityManager.getInstance().getTrainProjectsByPart(getContext(), classRecord.getTrainPart());
        ListDialog listDialog = new ListDialog(getContext());
        listDialog.setData(trainProjectsByPart);
        listDialog.setOnItemClickListener(this);
        listDialog.show();
    }

    @Override
    public void onItemClick(Dialog dialog, TrainProjectEntity t) {
        dialog.dismiss();
        String trainSubject = classRecord.getTrainSubject();
        if (trainSubject != null) {
            if (!trainSubject.contains(t.getProjectName())) {
                trainSubject = trainSubject + "," + t.getProjectName();
            }
        } else {
            trainSubject = t.getProjectName();
        }
        classRecord.setTrainSubject(trainSubject);
        String courseNum = classRecord.getCourseNum();
        StringBuilder sb = new StringBuilder(courseNum);
        sb.replace(4, 6, t.getProjectCode());
        classRecord.setCourseNum(sb.toString());
        ClassRecordDaoManager.getInstance().getClassRecordDao().update(classRecord);
    }

    @Override
    public void onCloseClick(Dialog dialog) {
    }

    /**
     * obd 连接状态
     * 在OBDGatewayService handler中发送事件
     *
     * @param connState obd
     */
    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void onEventObdConnState(ObdConnState connState) {
        switch (connState.state) {
            case ObdConnState.CONNECT_INIT:
                btnOdb.setSelected(false);
                tvObd.setText("正在连接");
                isObdConnSucess = false;
                break;
            case ObdConnState.CONNECT_FAIL:
                btnOdb.setSelected(false);
                tvObd.setText(R.string.failed);
                isObdConnSucess = false;
                break;
            case ObdConnState.CONNECT_NO_DEVICE:
                btnOdb.setSelected(false);
                tvObd.setText(R.string.dismatch_obd_device);
                isObdConnSucess = false;
                break;
            case ObdConnState.CONNECT_SUCCESS:
                btnOdb.setSelected(true);
                tvObd.setText(R.string.normal);
                isObdConnSucess = true;
                break;
        }
        EventBus.getDefault().removeStickyEvent(ObdConnState.class);
    }

    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void onEventObdDate(Map map) {
        btnOdb.setSelected(true);
        tvObd.setText(R.string.normal);
        isObdConnSucess = true;
        Log.e("harisucici", "RPM_" + map.get("RPM"));
        Log.e("harisucici", "KM_" + map.get("KM"));
        tvRotateSpeed.setText(map.get("RPM") + "r/min");
        tvAverageSpeed.setText(map.get("KM") + "km/h");
        EventBus.getDefault().removeStickyEvent(ObdConnState.class);
    }

    /**
     * 通道状态
     * ChannelListenerImpl  method :active/inactive
     *
     * @param code 服务连接状态
     */
    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void onEventChannelStatus(Integer code) {
        if (code == Const.CHANNEL_ACTIVE || code == Const.CHANNEL_INACTIVE) {
            EventBus.getDefault().removeStickyEvent(code);
            btnServer.setSelected(code == Const.CHANNEL_ACTIVE);
            tvServer.setText(code == Const.CHANNEL_ACTIVE ? "正常" : "断开");
        }
    }

    /**
     * GPS状态
     * LocationMgr  method: onLocationStatus
     *
     * @param gpsStatus GPS
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventGpsStatus(GpsStatusEntity gpsStatus) {
        if (gpsStatus != null) {
            tvGps.setText(gpsStatus.satelliteCount + "");
            btnGps.setSelected(GpsStatusEntity.GPS_EFFECTIVE == gpsStatus.status);
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventLocation(SecondLocation sl) {
        Logger.t(TAG).d("练车页收到location");
        if (preLocation == null) {
            preLocation = sl.location;
        }
        if (sl.location != null) {
            String speed = String.format("%.2f km/h", LocationUtils.conversionSpeedKmH(sl.location.getSpeed()));
            tvAverageSpeed.setText(speed);
            if (sl.location.getSpeed() > 0) {
                float distance = LocationMgr.getInstance().distance(preLocation, sl.location);
                learnTotalMile += distance;
                totalMileage += distance;
                oneMinuteMile += distance;
                oneMinuteMaxSpeed = Math.max(oneMinuteMaxSpeed, LocationUtils.conversionSpeedKmH(sl.location.getSpeed()) * 10);
                TerminalParameterDaoManager.getInstance().updateTerminalParameterById(128, String.valueOf(totalMileage));
            }
            preLocation = sl.location;
            if (!NetConst.RELEASE_SERVER) {
                debugData(sl.location);
            }
        }
    }

    /**
     * debug 学时数据
     *
     * @param location
     */
    private void debugData(Location location) {
        tvProvider.setText("定位类型：" + location.getProvider());
        tvLat.setText("经度：" + String.format("%.6f", location.getLatitude()));
        tvLon.setText("纬度：" + String.format("%.6f", location.getLongitude()));
        tvSpeed.setText("GPS速度：" + location.getSpeed());
        tvMinMileage.setText("分钟里程：" + String.format("%.2f", oneMinuteMile));
        tvMinSpeedKm.setText("分钟MaxS：" + String.format("%.2f", oneMinuteMaxSpeed * 10) + "km/h");
        tvMinSpeedHm.setText("分钟MaxS：" + String.format("%.2f", oneMinuteMaxSpeed) + "hm/h");
        tvAcc.setText("定位精度：" + location.getAccuracy());
        tvTotalMile.setText("总里程：" + totalMileage);
    }

    @Override
    public void onTimerStart(TimerTextView view, long startTime) {
        Logger.t(TAG).i("开始计时" + DateUtil.timestampStr(System.currentTimeMillis(), "HH:mm:ss"));
    }

    @Override
    public void onTick(TimerTextView view, long totalTime) {
        String totalMileStr = String.format("%.1fkm", learnTotalMile / 1000.0f);
        if (!TextUtils.isEmpty(totalMileStr) && tvCourseNum != null) {
            tvCourseNum.setText(totalMileStr);
        }
        if (totalTime % 2 == 0 && isObdConnSucess) {
            mRotate += TerminalApplication.getTerminalContext().getEngine_RPM();
        }
        classRecord.setStudyValidLong(totalTime);
        classRecord.setMileage((int) learnTotalMile);
        ClassRecordDaoManager.getInstance().update(classRecord);
    }

    @Override
    public void onTimerStop(TimerTextView view, long totalTime) {
        Logger.t(TAG).i("停止计时");
    }

    @Override
    public void onTimerEvent(TimerTextView view, int event) {
        switch (event) {
            case TimerTextView.EVENT_TWENTY_SECONDS://二十秒 重传失败的学时，并且是重传次数小于6的学时
                if (!isSimulate) {
                    tryUploadPeriod(false);
                }
                tryUploadRandomPhoto(false);
                break;
            case TimerTextView.EVENT_ONE_MINUTES://一分钟
                tempOneMinuteMaxSpeed = oneMinuteMaxSpeed;
                tempOneMinuteMile = oneMinuteMile;
                tvRotateSpeed.setText(mRotate / 60 + " r/min");
                oneMinuteMaxSpeed = 0;
                oneMinuteMile = 0;
                mRotate = 0;
                upLoadPeriodRecord();
                break;
            case TimerTextView.EVENT_EIGHT_MINUTES://8分钟
                Logger.t(TAG).d("开始抓拍8分钟照片");
                takeStudentZhuaPaiPhoto();
                break;
        }
    }

    /**
     * 重传学时记录
     * 如果为结束训练，则再次重传所有当前课程失败学时
     * 如果非结束训练，则重传小于重传次数的失败学时，如果达到重传次数则不传
     *
     * @param isEnd 是否为结束训练
     */
    private void tryUploadPeriod(final boolean isEnd) {
        if (isEnd) {
            DialogUtils.showProgressBarDialog(getContext(), R.string.try_upload_period);
        }
        List<PeriodRecord> periodRecords;
        if (isEnd) {
            periodRecordTempArray.clear();
            periodRecords = PeriodRecordDaoManager.getInstance().findAllUploadFailedPeriodRecord(classRecordId);
            endRetryPeriodRecordIds = new ArrayList<>(periodRecords.size());
            for (PeriodRecord periodRecord : periodRecords) {
                endRetryPeriodRecordIds.add(periodRecord.get_ID());
            }
            Logger.t("TryUpload").d("结束练车重传学时条数为：" + periodRecords.size());
        } else {
            periodRecords = PeriodRecordDaoManager.getInstance().findCanUploadFailedPeriodRecord(classRecordId);
            Logger.t("TryUpload").d("练车中重传学时条数为：" + periodRecords.size());
        }
        if (periodRecords.size() != 0) {
            Observable.fromArray(periodRecords)
                    .map(new Function<List<PeriodRecord>, RetryUploadResult>() {
                        @Override
                        public RetryUploadResult apply(List<PeriodRecord> periodRecords) throws Exception {
                            for (int i = 0; i < periodRecords.size(); i++) {
                                PeriodRecord periodRecord = periodRecords.get(i);
                                periodRecord.setTryCount(periodRecord.getTryCount() + 1);
                                PeriodRecordDaoManager.getInstance().update(periodRecord);
                                removeTempPeriodRecord(periodRecord.get_ID());
                                if (!isEndTrain && periodRecord.getTryCount() >= Const.TRY_COUNT) {
                                    continue;
                                }
                                if (TerminalSocketClientManager.getInstance().isAuthenticated()) {
                                    Terminal0x0203Transmission transmission = PeriodRecordDaoManager.getInstance().periodRecordTo0203Trans(periodRecord);
                                    if (transmission != null) {
                                        final Terminal0x0900Request req = messageUtil.buildTerminal0x0900Request(transmission, false, true);
                                        TerminalSocketClientManager.getInstance().tellAndSync(req);
                                        Integer sequence = req.getSeq();//tell的流水号
                                        if (null != sequence) {
                                            Logger.t("TryUpload").d("重传第 " + i + " 条学时 sequence:" + sequence + " id: " + periodRecord.get_ID());
                                            periodRecordTempArray.put(sequence, periodRecord.get_ID());
                                        }
                                    }
                                }
                            }
                            RetryUploadResult result = new RetryUploadResult(isEnd, RetryUploadResult.UPLOAD_PERIOD_OVER);
                            result.retryUploadPhotoCount = periodRecords.size();
                            return result;
                        }
                    }).observeOn(Schedulers.io())
                    .subscribeOn(Schedulers.io())
                    .subscribe(new Observer<RetryUploadResult>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                        }

                        @Override
                        public void onNext(RetryUploadResult o) {
                        }

                        @Override
                        public void onError(Throwable e) {
                            Logger.t("TryUpload").d("=========重传学时onError =====:" + e.getMessage());
                        }

                        @Override
                        public void onComplete() {
                            Logger.t("TryUpload").d("=========重传学时完毕 onComplete=====");
                        }
                    });
        } else if (isEnd) {
            RetryUploadResult result = new RetryUploadResult(isEnd, RetryUploadResult.UPLOAD_PERIOD_OVER);
            EventBus.getDefault().postSticky(result);
        }

    }

    private void removeTempPeriodRecord(Long periodRecordId) {
        int key = periodRecordTempArray.indexOfValue(periodRecordId);
        if (key >= 0) {
            periodRecordTempArray.remove(key);
        }
    }

    /**
     * 重传随机拍照
     *
     * @param isEnd 是否为结束训练
     */
    private void tryUploadRandomPhoto(boolean isEnd) {
        if (isEnd) {
            DialogUtils.showProgressBarDialog(getContext(), R.string.try_upload_photo);
        }
        RetryUploadPhoto photoEntity = new RetryUploadPhoto();
        photoEntity.photoEventType = Const.PhotoEventType.STUDENT_LEARNING;
        photoEntity.classRecordId = classRecordId;
        photoEntity.isEnd = isEnd;
        photoEntity.status = TakePhotoEntity.TAKE_PHOTO_SUCESS;
        EventBus.getDefault().postSticky(photoEntity);
    }

    /**
     * 上传学时记录
     */
    private synchronized void upLoadPeriodRecord() {
        if (isSimulate) {
            return;
        }
        try {
            final int tempMinuteMaxSpeed = Float.valueOf(tempOneMinuteMaxSpeed).intValue();
            float cacheMinuteMile = tempOneMinuteMile;
            if (cacheMinuteMile % 100 > 0) {
                cacheMinuteMile += 100;
            }
            final int tempMinuteMile = Float.valueOf(cacheMinuteMile / 100).intValue();
            ThreadManager.getInstance().getNormalPool().execute(new Runnable() {
                @Override
                public void run() {
                    //每一分钟上传一次学时记录
                    Terminal0x0203Transmission transmission = new Terminal0x0203Transmission();
                    String recordTime = DateUtil.timestampStr("HHmmss");
                    transmission.setRecordTime(recordTime);//记录产生时间HHmmss
                    String[] record = new BuildDataUtil().periodRecord();
                    transmission.setRecordNo(record[1]);
                    transmission.setType((short) 0x01);//上报类型
                    transmission.setUserNo(mStudentInfo.getUnifiedNum());
                    transmission.setCoachNo(coachInfo.getUnifiedNum());
                    transmission.setCourse(classRecord.getCourseNum());//课程编号
                    transmission.setClassId(classRecord.getClassId());//课堂ID
                    if (mIsCalcTime) {
                        transmission.setRecordStatus((short) 0);//记录状态 0：正常记录；1：异常记录
                    } else {
                        transmission.setRecordStatus((short) 1);
                    }
                    transmission.setMaxSpeed(tempMinuteMaxSpeed);
                    transmission.setMileage(tempMinuteMile);
                    transmission.setGnss(LocationUtils.getGnssPackage(LocationMgr.getBestLocation()));
                    transmission.setAttachementList(TerminalApplication.getTerminalContext().getLocationAttachement());
                    final long periodRecord_Id = PeriodRecordDaoManager.getInstance().insertPeriodRecord(transmission, record[0], classRecordId);
                    final Terminal0x0900Request req = messageUtil.buildTerminal0x0900Request(transmission, false, true);
                    TerminalSocketClientManager.getInstance().tellAndSync(req);
                    //harisucici 上报监管
                    TerminalSocketClientManager_8001.getInstance().tellWithNoAuth(req);

                    Integer sequence = req.getSeq();//tell的流水号
                    if (null != sequence) {
                        periodRecordTempArray.put(sequence, periodRecord_Id);
                        Logger.t("PeriodRecord").i("endRetryPeriodRecordIds: " + periodRecord_Id + "上传学时");
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventAbstractResponse(AbstractResponse response) {
        int msgId = response.getId();
        if (msgId == 0x900) {
            Integer sequence = response.getSequence();
            int result = response.getResult();
            if (0 == result) {
                Long uploadPeriodId = periodRecordTempArray.get(sequence);
                if (null != uploadPeriodId) {
                    periodRecordTempArray.remove(sequence);
                    PeriodRecordDaoManager.getInstance().updatePeriodRecordUploadState(uploadPeriodId, 1);
                    Logger.t("PeriodRecord").d("endRetryPeriodRecordIds : " + uploadPeriodId + " 的学时上传成功," + periodRecordTempArray.size() + "条未上传");
                    if (isEndTrain) {
                        endRetryPeriodRecordIds.remove(uploadPeriodId);
                        if (endRetryPeriodRecordIds.size() == 0) {
                            Logger.t("PeriodRecord").d("----------重传学时完成---------");
                            RetryUploadResult retryUploadResult = new RetryUploadResult(isEndTrain, RetryUploadResult.UPLOAD_PERIOD_OVER);
                            onEventRetryUploadResult(retryUploadResult);
                        }
                    }
                }
            }
        }
    }

    //学员签退
    public void tell0x0202Transmission() {
        Terminal0x0202Transmission ox0202 = new Terminal0x0202Transmission();
        ox0202.setUserNo(mStudentInfo.getUnifiedNum());
        ox0202.setTime(DateUtil.timestampStr(DateUtil.sf19));
        ox0202.setClassId(classRecord.getClassId());
        ox0202.setTotalTime((int) TimeUnit.SECONDS.toMinutes(classRecord.getStudyValidLong()));
        ox0202.setTotalMileage(classRecord.getMileage());
        ox0202.setGnssPackage(LocationUtils.getGnssPackage(LocationMgr.getBestLocation()));
        //harisucici 上报监管
        TerminalSocketClientManager_8001.getInstance().tellWithNoAuth(messageUtil.buildTerminal0x0900Request(ox0202, false, true));
        TerminalSocketClientManager.getInstance().tellWithNeedAuth(messageUtil.buildTerminal0x0900Request(ox0202, false, true));
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent0x8202Transmission(Terminal0x8202Transmission ox8202) {
        int result = ox8202.getResult();
        switch (result) {
            case 1:
            case 2:
                if (result == 2) {
                    showToast("登出失败");
                }
                BuildDataUtil.clearStudentClassId();
                StudentStudyRecordDaoManager.getInstance().updateStudentSignOutTime(studyLoginRecordId);
                ClassRecordDaoManager.getInstance().updateClassRecordSignStatus(classRecordId, ClassRecord.SIGN_OUT);
                LocationMgr.getInstance().resetRebootDeviceCondition();
                mActivity.switchFragment(Const.COACH_TRAIN_RECORD_FRAGMENT_TAG, coachLoginRecordId, "", true);
                break;
            case 9:
                showToast("其他错误");
                break;
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent0x0301Transmission(Terminal0x0301Transmission ox0301) {
        CameraActivity.startCameraActivity(mActivity
                , Const.TakePhotoMode.COUNT_DOWN_TIME
                , 2
                , Const.PhotoEventType.ZHUAPAI
                , classRecord.getTrainPart()
                , mStudentInfo.getName()
                , coachInfo.getName()
                , ox0301.getCameraChannel()
                , classRecordId, null, false);
    }

    /**
     * 学员登出拍照
     */
    public void takeStudentSignOutPhoto() {
        CameraMgr.startFaceCamera(getActivity(),
                mStudentInfo.getUnifiedNum(),
                Const.PhotoEventType.STUDENT_SIGN_OUT,
                classRecord.getTrainPart(),
                mStudentInfo.getName(),
                coachInfo.getName(),
                null);
    }

    //练车中8分钟拍照，模拟平台下发抓拍
    private void takeStudentZhuaPaiPhoto() {
        CameraActivity.startCameraActivity(mActivity
                , Const.TakePhotoMode.COUNT_DOWN_TIME
                , 2
                , Const.PhotoEventType.ZHUAPAI
                , classRecord.getTrainPart()
                , mStudentInfo.getName()
                , coachInfo.getName()
                , Const.CameraChannel.BACK
                , classRecordId, null, false);
    }

    /**
     * 保存抓拍照片信息
     *
     * @return
     */
    public long saveRandomPhotoInfo() {
        long randomPhotoTime = System.currentTimeMillis();
        Terminal0x0305Transmission transmission = new Terminal0x0305Transmission();
        transmission.setImageNo(DateUtil.timestampStr(randomPhotoTime, DateUtil.sf6));
        //1：平台拍照指令后上传自动请求上传；2：平台查询后要求上传；129：终端主动拍照上传；255：停止拍摄并上传图片
        transmission.setUploadType(Const.UploadPhotoType.TERMINAL_UPLOAD);
        transmission.setUserNo(mStudentInfo.getUnifiedNum());
        transmission.setClassId(BuildDataUtil.getStudentClassId());
        transmission.setCameraChannel((short) 0);
        transmission.setSize((short) 2);
        transmission.setEventType(Const.PhotoEventType.STUDENT_LEARNING);
        transmission.setGnss(LocationUtils.getGnssPackage(LocationMgr.getBestLocation()));
        transmission.setTrustable((short) 100);
        transmission.setAttachementList(TerminalApplication.getTerminalContext().getLocationAttachement());
        String trans = Util.parseObjectToGsonJson(transmission);
        RandomPhoto randomPhoto = new RandomPhoto();
        randomPhoto.setTakePhotoTimeStamp(randomPhotoTime);
        randomPhoto.setClassRecordId(classRecordId);
        randomPhoto.set_0305(trans);
        long randomPhotoId = RandomPhotoDaoManager.getInstance().insertRecord(randomPhoto);
        return randomPhotoId;
    }

    /**
     * 练车中随机拍照
     */
    public void takeStudentLearningPhoto(long randomPhotoId, boolean isEndSupplementPhoto) {
        CameraActivity.startCameraActivity(mActivity, Const.TakePhotoMode.COUNT_DOWN_TIME
                , 2, Const.PhotoEventType.STUDENT_LEARNING
                , classRecord.getTrainPart(), mStudentInfo.getName()
                , coachInfo.getName(), Const.CameraChannel.FONT
                , classRecordId, randomPhotoId, isEndSupplementPhoto);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();

        if (mHandler != null) {
            mHandler.removeCallbacks(runnable);
        }

//        if (mLedHandler != null) {
//            mLedHandler.removeCallbacks(ledRunnable);
//        }


        if (mIntervalTimeDisposable != null) {
            mIntervalTimeDisposable.dispose();
        }
        try {
            if (normalAlertDialog != null && normalAlertDialog.isShowing()) {
                normalAlertDialog.dismiss();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class EndTrainRunnable implements Runnable {
        private static final int MAX_TIME = 60;
        private int timeOut = MAX_TIME;
        private WeakReference<Button> endTrainBtn;
        private WeakReference<Handler> hwr;

        public EndTrainRunnable(Button btn, Handler handler) {
            endTrainBtn = new WeakReference<>(btn);
            hwr = new WeakReference<>(handler);
        }

        @Override
        public void run() {
            if (endTrainBtn != null && endTrainBtn.get() != null) {
                endTrainBtn.get().setText(timeOut-- + "s后再签退");
                if (timeOut <= 0) {
                    timeOut = MAX_TIME;
                    endTrainBtn.get().setEnabled(true);
                    endTrainBtn.get().setText("结束培训");
                } else {
                    if (hwr != null && hwr.get() != null) {
                        hwr.get().postDelayed(this, 1000);
                    }
                }
            }
        }
    }


    static class LedRunnable implements Runnable {
        private PL2303Driver mSerial;
        private Handler mHandler;
                private int delay = 60000;
//        private int delay = 5000;
        private Callback.Cancelable cancelable;
        private PL2303Driver.BaudRate mBaudrate = PL2303Driver.BaudRate.B19200;

        public LedRunnable(Handler handler, PL2303Driver serial) {
            mHandler = handler;
            mSerial = serial;
        }

        private void openUsbSerial(String s) {
            if (null == mSerial) {
                Toast.makeText(TerminalApplication.getTerminalContext(), "isComSerial_NULL ", Toast.LENGTH_SHORT).show();
                return;
            }
            if (mSerial.isConnected()) {
                Toast.makeText(TerminalApplication.getTerminalContext(), "isConnected ", Toast.LENGTH_SHORT).show();
                mBaudrate = PL2303Driver.BaudRate.B19200;
                if (!mSerial.InitByBaudRate(mBaudrate, 700)) {
                    if (!mSerial.PL2303Device_IsHasPermission()) {
                        Toast.makeText(TerminalApplication.getTerminalContext(), "cannot open, maybe no permission", Toast.LENGTH_SHORT).show();
                    }

                    if (mSerial.PL2303Device_IsHasPermission() && (!mSerial.PL2303Device_IsSupportChip())) {
                        Toast.makeText(TerminalApplication.getTerminalContext(), "cannot open, maybe this chip has no support, please use PL2303HXD / RA / EA chip.", Toast.LENGTH_SHORT).show();
                    }
                } else {

                    Toast.makeText(TerminalApplication.getTerminalContext(), "connected : ", Toast.LENGTH_SHORT).show();
                    setLedText(s);
                }
            }//isConnected
        }//openUsbSerial

        private List<Byte> makeTempdata28(String s) {
            char[] chars = s.toCharArray();
            byte tempData28Color = 0x01;
            byte tempData28Icon = 0x00;
            byte tempData28End = (byte) 0xff;
            int length = s.length();
            List<Byte> tempData28 = new ArrayList<>();
            for (int i = 0; i < length; i++) {
                tempData28.add(tempData28Color);
                tempData28.add(tempData28Icon);
                tempData28.add((byte) chars[i]);
            }
            tempData28.add(tempData28End);
            return tempData28;
        }


        private byte makeCheckNum(List<Byte> list) {
            int sum = 0;
            for (int i = 1; i < list.size(); i++) {
                sum = (sum + list.get(i));
            }
            sum = (sum % 256);
            return (byte) sum;

        }

        private void setLedText(String s) {
            if (null == mSerial)
                return;
            if (!mSerial.isConnected())
                return;
            List<Byte> list = new ArrayList<>();
            byte head = 0x79;
            byte command1 = 0x77;
            byte command2 = 0x00;
            byte addr = 0x00;
            byte rsMode = 0x00;
            byte cs = 0x00;
            byte id = 0x01;
            // data
            byte tempData1 = 0x00;
            byte tempData2 = 0x00;
            byte tempData3 = 0x00;
            List<Byte> tempData4to20 = new ArrayList<>();
            for (int i = 4; i < 21; i++) {
                byte temp = 0x00;
                tempData4to20.add(temp);
            }
            byte tempData21 = 0x00;
            byte tempData22 = 0x0A;
            byte tempData23 = 0x00;
            byte tempData24 = 0x01;
            byte tempData25 = 0x01;
            byte tempData26 = 0x05;
            byte tempData27 = 0x00;
            list.add(head);
            list.add(command1);
            list.add(command2);
            list.add(addr);
            list.add(rsMode);
            list.add(cs);
            list.add(id);
            list.add(tempData1);
            list.add(tempData2);
            list.add(tempData3);
            list.addAll(tempData4to20);
            list.add(tempData21);
            list.add(tempData22);
            list.add(tempData23);
            list.add(tempData24);
            list.add(tempData25);
            list.add(tempData26);
            list.add(tempData27);
            list.addAll(makeTempdata28(s));
            list.add(makeCheckNum(list));
            list.add(head);
            byte[] bytes = new byte[list.size()];
            for (int i = 0; i < list.size(); i++) {
                bytes[i] = list.get(i);
            }

            int res = mSerial.write(bytes, list.size());
            if (res < 0) {
                return;
            }
        }


        @Override
        public void run() {
            Log.e("harisucici", "GET_LED");
            cancelable = x.http().get(getLEDParams(), new Callback.CommonCallback<String>() {
                @Override
                public void onSuccess(String result) {
                    Log.e("harisucici", "LED成功");
                    if (result != null) {
                        //harisucici
                        LedBean ledBean = new Gson().fromJson(result, LedBean.class);
                        if (ledBean.getCode() == 0) {
                            Log.e("harisucici", "LEDURL:" + ledBean.getData().getCode());
                            openUsbSerial(ledBean.getData().getCode());
                        } else {
                            Log.e("harisucici", "LEDURL:" + "ERROR");
                            openUsbSerial("NO DATA");
                        }
                    }
                }

                @Override
                public void onError(Throwable ex, boolean isOnCallback) {
//                    openUsbSerial("ERROR");
                    Logger.t("harisucici").e("检查LEDOnError。" + ex.getMessage());
                }

                @Override
                public void onCancelled(CancelledException cex) {
//                    openUsbSerial("CANCEL");
                    Logger.t("harisucici").i("检查LED取消。");
                }

                @Override
                public void onFinished() {
//                    openUsbSerial("FINISH");
                    Logger.t("harisucici").i("检查LEDFinished");
                }
            });
            mHandler.postDelayed(this, delay);

        }


        private RequestParams getLEDParams() {
            TerminalBaseInfo terminalBaseInfo = TerminalBaseInfoDaoManager.getInstance().getTerminalBaseInfo();
            StringBuilder sb = new StringBuilder();
            sb.append(NetConst.GET_LED);
            sb.append(terminalBaseInfo.getDevice());
//            sb.append("3394412223422613");
            Log.e("harisucici", "检测LEDUrl:" + terminalBaseInfo.getDevice());
            RequestParams requestLEDParams = new RequestParams(sb.toString());
            return requestLEDParams;
        }
    }

    class ConnectivityChangedReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {

            if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {

                if (mNetWork != NetWorkUtils.getAPNType(context)) {
                    mNetWork = NetWorkUtils.getAPNType(context);
                    if (mAlivcLivePusher != null) {
                        if (mAlivcLivePusher.isPushing()) {
                            try {
                                mAlivcLivePusher.reconnectPushAsync(null);
                            } catch (IllegalStateException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }

        }
    }
}
